
#include <BChangeEvent>
#include <BObject>
#include "member_BObject.h"
#include "member_BWidget.h"

using namespace BWE;

#define member					(*(member_BObject*)_ptr)
#define member_allocate()		_ptr = new member_BObject(this)
#define member_release()		delete (member_BObject*)_ptr

BObject::BObject()
{
	member_allocate();
}
BObject::BObject(const BString& name)
{
	member_allocate();
	setName(name);
}
BObject::~BObject()
{
	member_release();
}

void BObject::setName(const BString& name)
{
	if (member.name != name)
	{
		member.name = name;
	}
}
const BString& BObject::name() const
{
	return member.name;
}

void BObject::setAble(bool able)
{
	if (able)
		enable();
	else
		disable();
}
bool BObject::able() const
{
	return member.able;
}

void BObject::enable()
{
	if (!member.able)
	{
		member.able = true;
		emit(Signal_Enable);
		if (BWidget* widget = dynamic_cast<BWidget*>(this))
		{
			BChangeEvent changeEvent(Change_Able);
			changeEvent.setAble(true);
			widget_member(widget)->procEvent(changeEvent);
		}
	}
}
void BObject::disable()
{
	if (member.able)
	{
		emit(Signal_Disable);
		member.able = false;
		if (BWidget* widget = dynamic_cast<BWidget*>(this))
		{
			BChangeEvent changeEvent(Change_Able);
			changeEvent.setAble(false);
			widget_member(widget)->procEvent(changeEvent);
		}
	}
}

bool BObject::lock()
{
	if(member.initMutex())
	{
#ifdef _LINUX_
		int error = pthread_mutex_lock(&member.mutex);
		return error == 0;
#else
		EnterCriticalSection(&member.criticalSection);
		return true;
#endif
	}
	return false;
}
bool BObject::unlock()
{
	if(member.initMutex())
	{
#ifdef _LINUX_
		int error = pthread_mutex_unlock(&member.mutex);
		return error == 0;
#else
		LeaveCriticalSection(&member.criticalSection);
		return true;
#endif
	}
	return false;
}
bool BObject::trylock()
{
	if(member.initMutex())
	{
#ifdef _LINUX_
		int error = pthread_mutex_trylock(&member.mutex);
		return error == 0;
#else
		BOOL ret = TryEnterCriticalSection(&member.criticalSection);
		return ret;
#endif
	}
	return false;
}

bool BObject::disconnect(int signal)
{
	SigSlotMap& globalSigSlotMap = member.globalSigSlotMap();
	if(signal == 0)
	{
		for (SigSlotArray& objects : globalSigSlotMap)
			objects.remove(this);
	}
	else
	{
		SigSlotArray& slots = globalSigSlotMap[signal];
		slots.remove(this);
	}
	return true;
}
bool BObject::disconnect(const BString& signal)
{
	StrSigSlotMap& globalStrSigSlotMap = member.globalStrSigSlotMap();
	if (signal.empty())
	{
		for (SigSlotArray& slots : globalStrSigSlotMap)
			slots.remove(this);
	}
	else
	{
		SigSlotArray& slots = globalStrSigSlotMap[signal];
		slots.remove(this);
	}
	return true;
}
bool BObject::disconnect(BObject* object, int signal)
{
	if (!object)
		return false;
	SigSlotMap& sigProcMap = object_member(object)->sigProcMap;
	if (signal)
	{
		SigSlotArray& slots = sigProcMap[signal];
		slots.remove(this);
	}
	else
	{
		for (SigSlotArray& slots : sigProcMap)
			slots.remove(this);
	}
	return true;
}
bool BObject::disconnect(BObject* object, const BString& signal)
{
	if (!object)
		return false;
	StrSigSlotMap& strSigSlotMap = object_member(object)->strSigSlotMap;
	if (signal.empty())
	{
		for (SigSlotArray& slots : strSigSlotMap)
			slots.remove(this);
	}
	else
	{
		SigSlotArray& slots = strSigSlotMap[signal];
		slots.remove(this);
	}
	return true;
}

bool BObject::emit(int signal, const BValue& value)
{
	if (!member.able || !signal)
		return false;
	SigSlotArray& slots = member.sigProcMap(signal);
	for (int i = 0; i < slots.size(); i++)
	{
		SigSlot& slot = slots[i];
		slot(this, value);
	}
	SigSlotMap& globalSigSlotMap = member.globalSigSlotMap();
	SigSlotArray& globalProcs = globalSigSlotMap(signal);
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigSlot& slot = globalProcs[i];
		slot(this, value);
	}
	return true;
}
bool BObject::emit(const BString& signal, const BValue& value)
{
	if (signal.empty())
		return false;
	SigSlotArray& slots = member.strSigSlotMap(signal);
	for (int i = 0; i < slots.size(); i++)
	{
		SigSlot& slot = slots[i];
		slot(this, value);
	}
	StrSigSlotMap& globalStrSigSlotMap = member.globalStrSigSlotMap();
	SigSlotArray& globalProcs = globalStrSigSlotMap(signal);
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigSlot& slot = globalProcs[i];
		slot(this, value);
	}
	return true;
}

bool BObject::post(BObject* object, int signal, const BValue& value)
{
	if (!object)
		return false;
	if (!signal)
		return false;
	SigSlotArray& slots = member.sigProcMap[signal];
	for (int i = 0; i < slots.size(); i++)
	{
		SigSlot& slot = slots[i];
		if (slot.object == object)
		{
			slot(this, value);
		}
	}
	SigSlotMap& globalSigSlotMap = member.globalSigSlotMap();
	SigSlotArray& globalProcs = globalSigSlotMap[signal];
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigSlot& slot = globalProcs[i];
		if (slot.object == object)
		{
			slot(this, value);
		}
	}
	return true;
}
bool BObject::post(BObject* object, const BString& signal, const BValue& value)
{
	if (!object)
		return false;
	if (signal.empty())
		return false;
	SigSlotArray& slots = member.strSigSlotMap[signal];
	for (int i = 0; i < slots.size(); i++)
	{
		SigSlot& slot = slots[i];
		if (slot.object == object)
		{
			slot(this, value);
		}
	}
	StrSigSlotMap& globalSigSlotMap = member.globalStrSigSlotMap();
	SigSlotArray& globalProcs = globalSigSlotMap[signal];
	for (int i = 0; i < globalProcs.size(); i++)
	{
		SigSlot& slot = globalProcs[i];
		if (slot.object == object)
		{
			slot(this, value);
		}
	}
	return true;
}

bool BObject::attach(int signal, slot method)
{
	if (signal == 0)
		return false;
	SigSlot sp(this, method);
	SigSlotMap& globalSigSlotMap = member.globalSigSlotMap();
	SigSlotArray& slots = globalSigSlotMap[signal];
	slots.append(sp);
	return true;
}
bool BObject::attach(BObject* object, int signal, slot method)
{
	if (!object || signal == 0)
		return false;
	SigSlot sp(this, method);
	SigSlotArray& slots = object_member(object)->sigProcMap[signal];
	if (!slots.contain(sp))
		slots.append(sp);
	return true;
}
bool BObject::attach(const BString& signal, slot method)
{
	if (signal.empty())
		return false;
	SigSlot sp(this, method);
	StrSigSlotMap& globalStrSigSlotMap = member.globalStrSigSlotMap();
	SigSlotArray& slots = globalStrSigSlotMap[signal];
	if (!slots.contain(sp))
		slots.append(sp);
	return true;
}
bool BObject::attach(BObject* object, const BString& signal, slot method)
{
	if (!object || signal.empty())
		return false;
	SigSlot sp(this, method);
	SigSlotArray& slots = object_member(object)->strSigSlotMap[signal];
	if (!slots.contain(sp))
		slots.append(sp);
	return true;
}


